package com.seleniti.enpareja.android.model.integration.gcm;

import java.util.Date;

import org.ioc.commons.flowcontrol.common.impl.ReceiverAdapter;
import org.ioc.commons.flowcontrol.logincontroller.IsLoggedUserInfoConsumer;
import org.ioc.commons.flowcontrol.logincontroller.LoginController;
import org.ioc.commons.flowcontrol.placecontroller.PlaceController;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gcm.GCMBaseIntentService;
import com.google.android.gcm.GCMRegistrar;
import com.seleniti.enpareja.android.control.entrypoint.EnParejaAndroid;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.control.controller.LoginFailedCause;
import com.seleniti.enpareja.controller.control.controller.LoginParams;
import com.seleniti.enpareja.controller.control.factory.ClientFactory;
import com.seleniti.enpareja.controller.model.integration.database.domain.Notification;
import com.seleniti.enpareja.controller.model.integration.gcm.Constants;
import com.seleniti.enpareja.controller.model.integration.service.EnParejaServiceManager;

/**
 * Intent which is handling GCM messages and registrations.
 */
public class GCMIntentService extends GCMBaseIntentService implements IsLoggedUserInfoConsumer<LoggedUserInfo> {
	private String registrationId;
	private ClientFactory clientFactory;
	private LoginController<LoggedUserInfo, LoginFailedCause, LoginParams, String> loginController;
	private PlaceController placeController;

	public GCMIntentService() {
		super("enParejaGCMService");
	}

	@Override
	public void onCreate() {
		super.onCreate();
		this.clientFactory = ((EnParejaAndroid) this.getApplication()).getClientFactory();
		this.loginController = clientFactory.getLoginController();
		this.placeController = clientFactory.getPlaceController().forThisObject(this);
	}

	@Override
	protected void onError(Context context, String arg1) {
		Log.d(TAG, "onError: " + arg1);
		// clientFactory.getExceptionController().h
		// TODO: Logar o mostrar error
	}

	@Override
	protected void onMessage(final Context context, Intent messageIntent) {
		Log.d(TAG, "onMessage: " + messageIntent);
		Bundle extras = messageIntent.getExtras();

		final String notificationId = extras.getString(Constants.NOTIFICATION_ID_KEY);
		final EnParejaServiceManager sm = clientFactory.getServiceManager();

		sm.serviceFactory().notificationService().find(notificationId).caller(this)
				.to(new ReceiverAdapter<Notification>() {

					@Override
					public void success(Notification result) {
						if (result == null) {
							/*
							 * No longer available
							 */
							return;
						}

						if (result.getServerDate() == null || result.getDate() == null
								|| result.getDate().before(result.getServerDate())) {
							/*
							 * It's time to notify
							 */
							Intent intent = new Intent(GCMIntentService.this, ScheduledService.class);
							intent.putExtra(Constants.NOTIFICATION_ID_KEY, notificationId);

							startService(intent);
						} else {
							/*
							 * We will notify it later
							 */
							AlarmManager manager = (AlarmManager) GCMIntentService.this
									.getSystemService(Context.ALARM_SERVICE);

							// (Modo no acoplado con un componente, ver

							Intent intent = new Intent(GCMIntentService.this, ScheduledService.class);
							intent.putExtra(Constants.NOTIFICATION_ID_KEY, notificationId);

							PendingIntent pIntent = PendingIntent.getBroadcast(GCMIntentService.this, 1, intent,
									PendingIntent.FLAG_UPDATE_CURRENT);

							long diff = result.getServerDate().getTime() - new Date().getTime();
							long millis = result.getDate().getTime() - diff;

							manager.set(AlarmManager.RTC, millis, pIntent);
						}

					}

				});

	}

	@Override
	protected void onRegistered(Context context, String registrationId) {
		// registrationId is something like this:
		// APA91bH6fqNq7-MmMdDaQLcegqa8vbqoPXcvqwso_owIFaUR794cl0gmRJr3n_nQEPqUwfR_HvxERUgQvVKXPN3HQoTt5_k8BMmeeWunKHsg8dBCxvMcIM0K6YndMX2DU4ne3STyOFRJjkeBynXL19yy7Dqn53UbNA
		Log.d(TAG, "onRegistered: " + registrationId);
		registerGCMClient(registrationId);
	}

	/**
	 * This is called when application first time registers for the GCM.<br/>
	 * <br/>
	 * This method registers on the opensource GCM4Public server
	 * 
	 * @param registrationId
	 * @param senderId
	 */
	private void registerGCMClient(String registrationId) {

		this.registrationId = registrationId;
		loginController.requiresLoggedUserInfo(this);
	}

	@Override
	protected void onUnregistered(Context arg0, String registrationId) {
		EnParejaServiceManager sm = clientFactory.getServiceManager();

		sm.serviceFactory().notificationService().unregisterDevice(registrationId).caller(this);
	}

	public static void registerAtGCM(Context context) {
		GCMRegistrar.checkDevice(context);
		GCMRegistrar.checkManifest(context);
		final String regId = GCMRegistrar.getRegistrationId(context);
		// if (regId.equals("")) {
		GCMRegistrar.register(context, Constants.SENDER_ID);
		// } else {
		// Log.v(TAG, "Already registered: " + regId);
		// }
	}

	@Override
	public void onLoggedUserInfoNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onLoggedUserInfoDataReady() {
		tryRegisterDeviceForLoggedUser();
	}

	protected void tryRegisterDeviceForLoggedUser() {
		if (loginController.isLogged() && registrationId != null) {
			// LoggedUserInfo lui = loginController.getLoggedUserInfo();
			EnParejaServiceManager sm = clientFactory.getServiceManager();

			sm.serviceFactory().notificationService().registerDeviceForLoggedUser(registrationId).caller(this)
					.to(new ReceiverAdapter<Boolean>() {

						@Override
						public void success(Boolean result) {
							if (!Boolean.TRUE.equals(result)) {
								boolean requiresInitializeLooper = Looper.myLooper() == null;
								if (requiresInitializeLooper) {
									Looper.prepare();
								}
								Toast.makeText(
										GCMIntentService.this,
										"No podrás recibir notificaciones de EnPareja.Net. Parece que el servicio de notificaciones no está disponible.",
										Toast.LENGTH_LONG).show();
								if (requiresInitializeLooper) {
									Looper.loop();
									if (Looper.myLooper() != null) {
										Looper.myLooper().quitSafely();
									}
								}
							}

						}
					});
		}
	}

	@Override
	public void onLoggedUserInfoDataUpdated(LoggedUserInfo loggedUserInfo) {
		tryRegisterDeviceForLoggedUser();
	}
}
